#include "kvstore2pcsystem.h"
#include "coordinator.h"
#include "participant.h"
#include "GLOBAL.h"
#include "parser.h"
#include "utils.h"
#include "GLOBAL.h"
#include "raft.h"
#include <iostream>
#include <unordered_map>
using namespace std;

std::vector<NodeInfo>   pinfo;
NodeInfo                cinfo;
std::vector<NodeInfo>   finfo;
NodeInfo                serverinfo;

unordered_map<int, int> port_ID_mp = {
    {8001, 1},
    {8002, 2},
    {8003, 3}
};
// 获取leader的id
int GetLeaderID(std::shared_ptr<raft::objfactory<raft::server>> factory)
{
    int leader_id = 0;
    int term = -1;
    for (const auto &id : factory->GetAllObjKey())
    {
        auto tmp = factory->Get(id, factory);
        if (tmp->IsStop())
            continue;

        // 在同一个任期内，只有一个leader
        if (!tmp->IsLeader())
            continue;
        if (leader_id == 0)
            leader_id = id;
        assert(leader_id == id);
    }
    return leader_id;
}

// 检测日志是否一致
void CheckApplyLog(std::shared_ptr<raft::objfactory<raft::server>> factory)
{
    const auto &leader_id = GetLeaderID(factory);
    assert(leader_id != 0);
    const auto &log_vec = factory->Get(leader_id, factory)->ApplyLogVec();
    for (const auto &id : factory->GetAllObjKey())
    {
        auto tmp = factory->Get(id, factory);
        if (tmp->IsStop())
            continue;

        const auto &tmp_log_vec = tmp->ApplyLogVec();
        assert(log_vec.size() == tmp_log_vec.size());
        for (int i = 0; i < (int)log_vec.size(); ++i)
        {
            assert(log_vec[i].ID == tmp_log_vec[i].ID);
            assert(log_vec[i].term == tmp_log_vec[i].term);
            assert(log_vec[i].is_server == tmp_log_vec[i].is_server);
            assert(log_vec[i].event == tmp_log_vec[i].event);
        }
    }
}
// 打印所有服务器的日志
void PrintAllApplyLog(std::shared_ptr<raft::objfactory<raft::server>> factory)
{
    for (const auto &id : factory->GetAllObjKey())
    {
        auto tmp = factory->Get(id, factory);
        if (tmp->IsStop())
            continue;
        tmp->PrintAllLog();
    }
}
// 打印所有服务器的KV
void PrintAllKV(std::shared_ptr<raft::objfactory<raft::server>> factory)
{
    for (const auto &id : factory->GetAllObjKey())
    {
        auto tmp = factory->Get(id, factory);
        if (tmp->IsStop())
            continue;
        tmp->KVPrint();
    }
}

/*
main：主函数入口
1. 根据配置文件创建kvstore2pcsystem
2. 根据配置文件创建对应Coordinator、myParticipant结点
*/
bool cmp(const NodeInfo& a, const NodeInfo& b) {
    return a.port < b.port;
}

int main(int argc, char * argv[]) {
    if(argc == 0) {
        std::cout << "> ERROR: UNDEFINE INPUT. AT LEAST ONE ARGUMENT IS REQUIRED. " << std::endl;
    }
    else if(argc == 1) {
        std::string add = SERVER_ADD;
        ossSocket client;
        std::string msg;
        Parser p;

        while(getline(std::cin, msg)) {
            client = ossSocket(add.c_str(), 8001);

            client.initSocket();
            while( client.connect() ) { }
            if(G_DE_BUG) 
                printf("client connect success\n");
            std::vector<std::string> list;
            split(msg, list, ' ');       

            std::string pac = p.getRESPArry(list);
            client.send(pac.c_str(), pac.length(), 100000000);

            char * p = new char[1024];
            memset(p, 0, 1024);
            int len = 1024;
            while(client.recvNF(p, len, 100000)) {}

            std::string msg2(p, len);
            std::cout << msg2;

            delete[] p;
            msg.clear();
        }
        
        return 0;
    }
    if(argc == 2) {
        serverinfo.add = SERVER_ADD;
        serverinfo.port = SERVER_PORT;
        for(int i = 8001; i <= 8003; i++) {
            NodeInfo ninfo;
            ninfo.add = "127.0.0.1";
            ninfo.port = i;
            finfo.push_back(ninfo);
        }

    }
    
    serverinfo.add = SERVER_ADD;
    serverinfo.port = SERVER_PORT;
    kvstore2pcsystem KVSRAFT(argc, argv);
    int m = KVSRAFT.getMode();
    pinfo = KVSRAFT.getPinfo();
    cinfo = KVSRAFT.getCinfo();
    finfo = KVSRAFT.getFinfo();
    
    std::setbuf(stdout, nullptr);
    // 对象池
    auto factory = std::make_shared<raft::objfactory<raft::server>>();
    // // 线程池
    // auto &tpool = raft::thread_pool::get(100);
    // auto print = factory->Get(0, factory);
    // tpool.submit([print]
    //              { print->Print(); });
    // std::thread print_thread([print] { print->Print(); });

    if(G_DE_BUG){
        cout << KVSRAFT.getConf() << endl; 
        cout << "mode = " << KVSRAFT.getMode() << endl;
    }
    if(m == MODE_INVALID) {
        std::cout << "> ERROR: UNDEFINE MODE. " << std::endl;
        return 0;
    }
    else if(m == MODE_RAFT) {
        std::cout << "> RAFT. " << std::endl;
        int MAX_SERVER = (int)finfo.size();
        sort(finfo.begin(), finfo.end(), cmp);
        int id = port_ID_mp[pinfo[0].port];
        if(G_DE_BUG)  
            printf("follower is %d\n", pinfo[0].port);
        factory->Get(id, factory)->Start(finfo, pinfo[0]);
    }


    return 0;
    
}

    // 对象池
    // auto factory = std::make_shared<raft::objfactory<raft::server>>();

    // // 线程池
    // auto &tpool = raft::thread_pool::get(100);

    // // 打印线程
    // auto print = factory->Get(0, factory);
    // tpool.submit([print]
    //             { print->Print(); });

    // const auto &MAX_SERVER = 3;

    // // 服务器启动，选举出一个leader
    // print->AddPrint("\n\nTest->ALL server Start, server_count:" + std::to_string(MAX_SERVER));
    // for (int i = 1; i <= MAX_SERVER; ++i)
    //     factory->Get(i, factory)->Start();
    // std::this_thread::sleep_for(std::chrono::seconds(15));
    // const auto &leader1 = GetLeaderID(factory);
    // assert(leader1 != 0);
    // // 领导掉线，重新选举
    // print->AddPrint("\n\nTest->Server:" + std::to_string(leader1) + " Disconnect");
    // factory->Get(leader1, factory)->Stop();
    // std::this_thread::sleep_for(std::chrono::seconds(10));
    // const auto &leader2 = GetLeaderID(factory);
    // assert(leader2 != 0);

    // // 追加日志，掉线的服务器无法完成同步的
    // print->AddPrint("\n\nTest->Server:" + std::to_string(leader2) + " Add Log");
    // factory->Get(leader2, factory)->AddLog("test_1");
    // std::this_thread::sleep_for(std::chrono::seconds(10));
    // assert(factory->Get(leader1, factory)->ApplyLogVec().size() == 0);
    // CheckApplyLog(factory);

    // // 掉线的服务器重新上线，同步日志
    // print->AddPrint("\n\nTest->Server:" + std::to_string(leader1) + " Connect");
    // factory->Get(leader1, factory)->ReStart();
    // std::this_thread::sleep_for(std::chrono::seconds(10));
    // CheckApplyLog(factory);

    // // 超过一半的服务器掉线，无法完成选举
    // print->AddPrint("\n\nTest->Leader:" + std::to_string(leader2) + " And More Than Half Server Disconnect");
    // factory->Get(leader2, factory)->Stop();
    // int disconnect_count = MAX_SERVER / 2;
    // for (const auto &id : factory->GetAllObjKey())
    // {
    //     auto tmp = factory->Get(id, factory);
    //     if (tmp->IsStop())
    //         continue;
    //     tmp->Stop();
    //     if (--disconnect_count <= 0)
    //         break;
    // }
    // std::this_thread::sleep_for(std::chrono::seconds(3));
    // assert(GetLeaderID(factory) == 0);

    // // 上线一台服务器，超过一半的服务器上线，重新选举
    // print->AddPrint("\n\nTest->Server:" + std::to_string(leader2) + " Connect");
    // factory->Get(leader2, factory)->ReStart();
    // std::this_thread::sleep_for(std::chrono::seconds(10));
    // const auto &leader3 = GetLeaderID(factory);
    // assert(leader3 != 0);

    // // 下线一台非领导的服务器
    // print->AddPrint("\n\nTest->Disconnect One Server");
    // for (const auto &id : factory->GetAllObjKey())
    // {
    //     auto tmp = factory->Get(id, factory);
    //     if (!tmp->IsStop() && !tmp->IsLeader())
    //     {
    //         tmp->Stop();
    //         break;
    //     }
    // }
    // std::this_thread::sleep_for(std::chrono::seconds(3));

    // // 超过一半的服务器掉线，无法完成日志同步
    // print->AddPrint("\n\nTest->Add Log");
    // factory->Get(leader3, factory)->AddLog("test_2");
    // factory->Get(leader3, factory)->AddLog("test_3");
    // std::this_thread::sleep_for(std::chrono::seconds(10));
    // CheckApplyLog(factory);

    // // 所有掉线的服务器重新上线，同步日志
    // print->AddPrint("\n\nTest->All Server Connect");
    // for (const auto &id : factory->GetAllObjKey())
    // {
    //     auto tmp = factory->Get(id, factory);
    //     if (tmp->IsStop() && id != 0)
    //         tmp->ReStart();
    // }
    // std::this_thread::sleep_for(std::chrono::seconds(10));
    // CheckApplyLog(factory);

    // // 打印所有服务器的日志
    // print->AddPrint("\n\nTest->All Server Print Apply Log");
    // for (const auto &id : factory->GetAllObjKey())
    // {
    //     auto tmp = factory->Get(id, factory);
    //     if (!tmp->IsStop() && id != 0)
    //         tmp->PrintAllApplyLog();
    // }
